package com.xyht.sca_s.student_manage_system.common.desEncodeAndDecode;

import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ExceptionCast;
import com.xyht.sca_s.student_manage_system.common.desEncodeAndDecode.annotation.SecretBody;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

import static com.xyht.sca_s.student_manage_system.common.desEncodeAndDecode.constant.ConfigConstant.*;

@Slf4j
@ControllerAdvice
//@ConditionalOnProperty(prefix = "faster.secret", name = "enabled", havingValue = "true")
@Order(1)
@Component
public class SecretRequestAdvice extends RequestBodyAdviceAdapter {
    @Autowired
    private DesCbcUtil desCbcUtil;
    @Value("${config.decode_scan_switch}")
    private boolean decode_scan_switch;

    private Class<? extends Annotation> annotationClass = SecretBody.class;


    /**
     * 是否支持加密消息体
     *
     * @param methodParameter methodParameter
     * @return true/false
     */
    private boolean supportSecretRequest(MethodParameter methodParameter) {
        if (decode_scan_switch) {
            //判断class是否存在注解
            if (methodParameter.getContainingClass().getAnnotation(annotationClass) != null) {
                return true;
            }
            //判断方法是否存在注解
            return methodParameter.getMethodAnnotation(annotationClass) != null;
        }else{
            return false;
        }
    }


    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return supportSecretRequest(methodParameter);
//        return SCAN_ANNOTATION;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        //如果支持加密消息，进行消息解密。
        log.debug("进来了+++++++++++++++++++++++");
        boolean supportSafeMessage = supportSecretRequest(parameter);
        String httpBody;
        //每次读inputStream的大小
        byte[] buffer = new byte[1024];
        //创建内存节点输出流，将inputStream写到baos里，也就是将流保存至内存中，
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        int len;
        while ((len = inputMessage.getBody().read(buffer)) > -1)
        {
            outputStream.write(buffer, 0, len);
        }
        outputStream.flush();
        InputStream stream = new ByteArrayInputStream(outputStream.toByteArray());
        InputStream streamBack = new ByteArrayInputStream(outputStream.toByteArray());
        outputStream.close();
        if (supportSafeMessage) {
            httpBody = decryptBody(stream);
            if (httpBody == null) {
                log.debug("原数据返回+++++++++++++++++++++++");
                String encryptBody = StreamUtils.copyToString(streamBack, Charset.defaultCharset());
//                return new SecretHttpMessage(new ByteArrayInputStream(encryptBody.getBytes()), inputMessage.getHeaders());
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.DATA_DECODE_FAIL));
            }
        } else {
            httpBody = StreamUtils.copyToString(streamBack, Charset.defaultCharset());
        }
        //返回处理后的消息体给messageConvert
        return new SecretHttpMessage(new ByteArrayInputStream(httpBody.getBytes()), inputMessage.getHeaders());
    }

    /**
     * 解密消息体,3des解析（cbc模式）
     *
     * @return 明文
     */
    private String decryptBody(InputStream encryptStream) throws IOException {
//        InputStream encryptStream = inputMessage.getBody();
        String encryptBody = StreamUtils.copyToString(encryptStream, Charset.defaultCharset());
        return desCbcUtil.decode(encryptBody, DES_SECRET_KEY, DES_IV);
    }

}
